#ifndef __UNIT_H__
#define __UNIT_H__
#include <iostream>
using namespace std;


template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
class Unit
{
public:
    Unit(UNIT unit);
    unsigned long factor() const;
    static Unit baseUnit();
    static Unit topUnit();
    bool operator == (const Unit &unit);
    bool operator != (const Unit &unit);
    Unit operator ++ ();
    Unit operator -- ();
    ostream & operator << (ostream & out) const;

private:
    UNIT m_unit;
};

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
ostream& operator << (ostream& out, const Unit<UNIT, unitFactor, unitName, unitNumber> unit);

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
Unit<UNIT, unitFactor, unitName, unitNumber>::Unit (UNIT unit) :
    m_unit(unit)
{
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
unsigned long Unit<UNIT, unitFactor, unitName, unitNumber>::factor() const
{
    return unitFactor[m_unit];
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
Unit<UNIT, unitFactor, unitName, unitNumber> Unit<UNIT, unitFactor, unitName, unitNumber>::baseUnit()
{
    return Unit((UNIT)0);
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
Unit<UNIT, unitFactor, unitName, unitNumber> Unit<UNIT, unitFactor, unitName, unitNumber>::topUnit()
{
    return Unit((UNIT)(unitNumber - 1));
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
ostream & Unit<UNIT, unitFactor, unitName, unitNumber>::operator << (ostream & out) const
{
    return out << unitName[m_unit];
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
bool Unit<UNIT, unitFactor, unitName, unitNumber>::operator == (const Unit &unit)
{
    return m_unit == unit.m_unit;
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
bool Unit<UNIT, unitFactor, unitName, unitNumber>::operator != (const Unit &unit)
{
    return m_unit != unit.m_unit;
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
Unit<UNIT, unitFactor, unitName, unitNumber> Unit<UNIT, unitFactor, unitName, unitNumber>::operator ++ ()
{
    if ((unsigned long)m_unit < unitNumber)
    {
        m_unit = (UNIT) ((unsigned long)m_unit + 1);
    }
    return *(this);
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
Unit<UNIT, unitFactor, unitName, unitNumber> Unit<UNIT, unitFactor, unitName, unitNumber>::operator -- ()
{
    if ((unsigned long)m_unit > 0)
    {
        m_unit = (UNIT) ((unsigned long)m_unit - 1);
    }
    return *(this);
}

template<typename UNIT, const unsigned long unitFactor[], const char *unitName[], const unsigned long unitNumber>
ostream& operator << (ostream& out, const Unit<UNIT, unitFactor, unitName, unitNumber> unit)
{
    return unit << (out);
}


#endif


